;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                        ;;
;;  VGA.INC                                               ;;
;;  640x480 mode 0x12 VGA functions for MenuetOS          ;;
;;  Paul Butcher, paul.butcher@asa.co.uk                  ;;
;;                                                        ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   
paletteVGA:
   
    ; 16 colour palette

    mov   dx,0x3c8
    mov   al,0
    out   dx,al
   
    mov   ecx,16
    mov   dx,0x3c9
    xor   eax,eax
   
  palvganew:
   
    mov   al,0
    test  ah,4
    jz    palvgalbl1
    add   al,31
    test  ah,8
    jz    palvgalbl1
    add   al,32

  palvgalbl1:

    out   dx,al  ; red 0,31 or 63
    mov   al,0
    test  ah,2
    jz    palvgalbl2
    add   al,31
    test  ah,8
    jz    palvgalbl2
    add   al,32

  palvgalbl2:

    out   dx,al  ; blue 0,31 or 63
    mov   al,0
    test  ah,1
    jz    palvgalbl3
    add   al,31
    test  ah,8
    jz    palvgalbl3
    add   al,32

  palvgalbl3:

    out   dx,al  ; green 0,31 or 63
    add   ah,1
    loop  palvganew
   
    ret
   
vga_putimage:
   
    push  ebp ;
    push  esi ;
    push  edi ;
   
    push  eax ;
    push  ebx ; +8 [ptrImage]
    push  ecx ; +4 [BH]
    push  edx ; +0 [xy]
   
    movzx eax,word [esp+2]   ; eax:=x
    movzx ebx,word [esp+0]   ; ebx:=y
    mov   ecx,[0x3010]       ;
    add   eax,[ecx-twdw]     ; eax+=Xwin
    add   ebx,[ecx-twdw+4]   ; ebx+=Ywin
    mov   ecx,ebx            ; ecx = y+Ywin
    mov   edx,eax            ; edx = x+Xwin
   
    imul  ebx, 640*4          ; (y+Ywin)*BytesPerScanLine
    shl   eax,2               ; (x+Xwin)*BytesPerPixel
    add   eax,ebx             ;
    mov   edi,eax             ; store copy
    add   eax,[0xfe80]        ; +AddrLFB

    ;entry point in LFB >> EAX:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel+AddrLFB
   
    shr   edi,5                ; change from 4 to 1/8 BytesPerPixel
    add   edi,0xa0000          ; + VGABasePtr

    ;VGA start address >> EDI:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel+AddrVGA
   
    mov   ebx, [0xfe00]        ; ScreenXSize
    inc   ebx                  ; +1
    imul  ebx,ecx              ; *(y+Ywin)
    mov   ebp, ebx             ;
    add   ebp, edx             ; +(x+Xwin)
    add   ebp, 0x400000        ; ebp:=(y+Ywin)*(ScreenXSize+1)+(x+Xwin)+AddrBuffer
   
    mov   esi,[esp+8] ; esi:=AddrImg
    movzx ecx,word [esp+6] ; ecx:=B
    movzx ebx,word [esp+4] ; ebx:=H
   
    ; Check limits while draw ?
   
    push  ecx ; B
    push  eax ; LFB address
   
    mov   eax,[0x3010]
    mov   ecx,[eax+draw_data-0x3000+0]
    cmp   ecx,0
    jnz   dbcblimitlset_vga
   
    mov   ecx,[eax+draw_data-0x3000+4]
    cmp   ecx,0
    jnz   dbcblimitlset_vga
   
    mov   ecx,[eax+draw_data-0x3000+8]
    cmp   ecx,[0xfe00] ; ecx <> Screen X size
    jnz   dbcblimitlset_vga
   
    mov   ecx,[eax+draw_data-0x3000+12]
    cmp   ecx,[0xfe04] ; ecx <> Screen Y size
    jnz   dbcblimitlset_vga
   
    pop   eax ; LFB address
    pop   ecx ; B
   
    push  dword 0
   
    jmp   pimvga
   
  dbcblimitlset_vga:
   
    pop   eax ; LFB address
    pop   ecx ; B
   
    push  dword 1
   
pimvga:

    push  edi
    push  esi
    push  eax  ; LFB address
    push  ecx  ; B
    push  ebx  ; H
    push  edx  ; x+Xwin
   
    mov   ebx,[0x3010]
    mov   bl,[ebx+0xe]
    mov   bh,[esp+6*4]
   
    cld
   
 npvga:
   
    cmp   bl,[ds:ebp]
    jnz   impvgano
   
    cmp   bh,0
    jz    impvgayes
   
    call  voodoodbcplimit
    jnz   impvgano
   
 impvgayes:
   
    push  eax  ; LFB address
    push  ebx  ; app no.
    push  ecx  ; B
    push  edx  ; x+Xwin
   
    mov   edx,[esi] ; color
    mov   [eax],dx
    shr   edx,16
    mov   [eax+2],dl
   
    mov   eax,[esi]   ; color
    mov   ecx,[esp]   ; x+Xwin
    and   ecx,0x07    ; modulo 8
    call  setvgapixel ; eax=color, ecx=x%8, edi=VGA address
   
    pop   edx
    pop   ecx
    pop   ebx
    pop   eax
   
  impvgano:
   
    add   esi,3 ; esi+=3 ptrImage+=3
    add   eax,4 ; eax+=4 LFBaddr +=4
    inc   ebp
    inc   edx ; x+Xwin+n
   
    test  edx,0x07  ; test modulo 8
    jnz   impvgacont
    inc   edi
   
  impvgacont:

    dec   ecx ; B--
    jnz   npvga
   
    pop   edx
    pop   ebx
    pop   ecx
    pop   eax
    pop   esi
    pop   edi
   
    add   edi,640/8  ; add one VGA line
    add   eax,640*4  ; add one LFB line
   
    sub   ebp, ecx ;  -B
    add   ebp, [0xfe00] ;
    inc   ebp ; ptrBuffer:=ptrBuffer-B+Screen_Xsize+1
   
    push  ecx
    lea   ecx,[ecx+ecx*2] ;
    add   esi,ecx ; ptrImage:=ptrImage+B*3
    pop   ecx
 
    dec   ebx ; H--
    jnz   near pimvga
   
    add   esp,4  ; jump saved limit byte
    pop   edx
    pop   ecx
    pop   ebx
    pop   eax
    pop   edi
    pop   esi
    pop   ebp
   
    ret
   
   
VGA_putpixel:
   
    ; eax = x
    ; ebx = y
   
    mov   ecx,eax
    mov   eax, [esp+32-8+4] ; color
   
    imul  ebx, 640*4        ; y*BytesPerLine (Vesa2.0 32)
    lea   edx, [ebx+ecx*4]  ; + x*BytesPerPixel (Vesa2.0 32)
   
    mov   edi,edx
    add   edi, [0xfe80]     ; + LFB address
    mov   [edi], eax        ; write to LFB for Vesa2.0
   
    shr   edx,5             ; change BytesPerPixel to 1/8
    mov   edi,edx
    add   edi, 0x0a0000     ; address of pixel in VGA area
   
    and   ecx,0x07          ; bit no. (modulo 8)
   
setvgapixel:
   
    ; edi = address, eax = 24bit colour, ecx = bit no. (modulo 8)
   
    push  eax
    mov   ebx,eax            ; color
   
    ;mov    al,0x08
    ;mov    dx,0x03ce
    ;out    dx,al            ; select GDC bit mask register
   
    inc   cl
    mov   ax, 0x100
    shr   ax,cl
    mov   dx,0x03cf
    out   dx,al              ; set bit mask for pixel
   
    mov   dl,0
    mov   eax,ebx
    and   eax,0x000000ff     ; blue
    cmp   eax,85
    jle   p13green
    or    dl,0x01
    cmp   eax,170
    jle   p13green
    or    dl,0x08
   
p13green:

    and   ebx,0x0000ff00     ; green
    cmp   ebx,85*256
    jle   p13red
    or    dl,0x02
    cmp   ebx,170*256
    jle   p13red
    or    dl,0x08
   
p13red:

    pop   ebx
    and   ebx,0x00ff0000     ; red
    cmp   ebx,85*256*256
    jle   p13cont
    or    dl,0x04
    cmp   ebx,170*256*256
    jle   p13cont
    or    dl,0x08
   
p13cont:

    mov   al,[edi]           ; dummy read
    mov   [edi],dl
   
    ret
   
vga_drawbar:
   
    sub   edx,ebx ; edx:=Yend-Ystart=H
    sub   ecx,eax ; ecx:=Xend-Xstat=B
   
    push  ebp ; +24
    push  esi ; +20
    push  edi ; +16
    push  eax ; +12
    push  ebx ; +8
    push  ecx ; +4
    push  edx ; +0
   
    mov   ecx,[0x3010] ;
    add   eax,[ecx-twdw] ; eax:=Xwin+x
    add   ebx,[ecx-twdw+4] ; ebx:=Ywin+y
    mov   ecx, eax ; ecx:=(x+Xwin)
    mov   edx, ebx ; edx:=(y+Ywin)
   
    imul  ebx, 640/8  ;
    mov   edi, ebx ; edi:=BytesPerScanLine*(y+Ywin)
    shr   eax, 3 ;
    add   edi, eax ;  + (x+Xwin)*BytesPerPixel
    add   edi,0xa0000  ; + VGAbaseaddress
   
    mov   eax, [0xfe00] ; ScreenXSize
    inc   eax           ; +1
    imul  eax,edx       ; *(y+Ywin)
    mov   ebp, eax      ;
    add   ebp, ecx      ; +(x+Win)
    add   ebp, 0x400000 ; +AddrBuffer
   
    mov   eax, [0xfe08]  ; BytesPerScanLine - LFB
    mul   edx            ; *(y+Ywin)
    mov   esi,eax
    add   esi,ecx
    add   esi,ecx
    add   esi,ecx
    add   esi,ecx        ; + 4*(x+Xwin)
    add   esi,[0xfe80]   ; +AddrLFB
   
; edi:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel + AddrVGA
; esi:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel + AddrLFB
; ebp:=(y+Ywin)*(ScreenXSize+1)+(x+Xwin)+AddrBuffer
   
; x size
   
    mov   eax,[esp+4] ; B [esp+4]
    mov   ebx,[esp+0] ; H
   
    mov   edx,[esp+16] ; color
    test  edx,0x80000000
    jz    nodbglvga
   
    ; no color glide for VGA - set to half glide

    shr   ebx,1  ; H/2
    sub   edx,ebx
    mov   [esp+16],edx
    mov   ebx,[esp+0] ; reset to H
   
   nodbglvga:

    ; check limits ?
   
    push  eax
    push  ecx
   
    mov   eax,[0x3010]
   
    mov   ecx,[eax+draw_data-0x3000+0]
    cmp   ecx,0
    jnz   dbcblimitlset_vga2
   
    mov   ecx,[eax+draw_data-0x3000+4]
    cmp   ecx,0
    jnz   dbcblimitlset_vga2
   
    mov   ecx,[eax+draw_data-0x3000+8]
    cmp   ecx,[0xfe00]
    jnz   dbcblimitlset_vga2
   
    mov   ecx,[eax+draw_data-0x3000+12]
    cmp   ecx,[0xfe04]
    jnz   dbcblimitlset_vga2
   
    pop   ecx
    pop   eax
   
    push  dword 0
   
    jmp   dbnewpivga
   
  dbcblimitlset_vga2:
   
    pop   ecx ; x+Xwin
    pop   eax ; B
   
    push  dword 1
   
  dbnewpivga:
   
    push  eax; B
    push  ebx ; H
    push  edi
    push  esi
    push  ecx ; x+Xwin
   
    mov   ebx,[0x3010]
    movzx ebx,byte[ebx+0xe]
   
    cld
   
  dbnpvga:
   
    mov   dl,[ds:ebp]
   
    cmp   dl,bl
    jnz   dbimpvgano
 
    mov   edx,[esp+5*4] ; check limit?
    cmp   edx,0
    jz    dbimpvgayes
   
    call  voodoodbcplimit
    jnz   dbimpvgano
   
  dbimpvgayes:
   
    push  eax ; B
    push  ebx
    push  ecx ; x+Xwin
   
    mov   eax,[esp+12+20+16+4] ; color
    mov   ebx,eax
   
    mov   [esi],bx    ; write LFB pixel
    shr   ebx,16
    mov   [esi+2],bl
   
    and   ecx,0x07 ; modulo 8
    call  setvgapixel ; eax=color, ecx=x%8, edi=VGA address
 
    pop   ecx
    pop   ebx
    pop   eax
 
  dbimpvgano:
   
    add   esi,4    ; ptrLFB+=4
    inc   ebp      ; address buffer
    inc   ecx      ; x posn++
    test  ecx,0x07 ; test modulo 8
    jnz   dbvgacont
    inc   edi      ; VGA screen ptr++
   
  dbvgacont:

    dec   eax      ; B--  NB ecx in Vesa20 fn?
    jnz   dbnpvga
   
  dbnpvgad:
   
    pop   ecx
    pop   esi
    pop   edi
    pop   ebx
    pop   eax
   
    add   esi,[0xfe08]            ; ptrLFB+=BytesPerScanLine
    add   edi,640/8               ; ptrScreen+=BytesPerScanLine
   
    add   ebp,[0xfe00]            ;
    sub   ebp, eax                ; was ecx in vesa20 fn?
    inc   ebp                     ; ptrBuffer:=ptrBuffer-B+BytesPerLine+1
   
    dec   ebx                     ; H--
    jz    nodbnewpivga            ; H<>0
   
    jmp   dbnewpivga
   
  nodbnewpivga:
   
    add   esp,7*4   ; NB includes limit check flag
    ;pop   ebx
    ;pop   eax
    ;pop   edi
    ;pop   esi
    pop   ebp
   
    ;pop   edx
    ;pop   ecx
   
    ret
   
vga_drawbackground_tiled:
   
    push  ebp
    push  eax
    push  ebx
    push  ecx
    push  edx
   
    mov   edx,dword [0x400000-8] ; B
    add   edx,dword [0x400000-8] ; +B
    add   edx,dword [0x400000-8] ; +B
    push  edx
   
    mov   eax,[draw_data+32+0] ; x start:=(x+Xwin)
    mov   ebx,[draw_data+32+4] ; y start:=(y+Ywin)
    mov   ecx,eax
    mov   edx,ebx
   
    imul  edx, 640*4          ; (y+Ywin)*BytesPerScanLine
    shl   ecx,2               ; (x+Xwin)*BytesPerPixel
    add   ecx,edx             ;
    mov   ebp,ecx             ; store copy
    add   ecx,[0xfe80]        ; +AddrLFB

    ;entry point in LFB >> ECX:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel+Addr
   
    shr   ebp,5                ; change from 4 to 1/8 BytesPerPixel
    add   ebp,0xa0000          ; + VGABasePtr

    ;VGA start address >> EBP:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel+AddrV
   
    call  calculate_edi
   
  dp3vga:                           ; MAIN LOOP
   
    cmp   [edi+0x400000],byte 1     ; ptrBuffer^<>byte(1)
    je    ybgpvga
   
    jmp   nbgpvga
   
  ybgpvga:
   
    push  eax  ; x
    push  ebx  ; y
    push  ecx  ; LFB address
   
    mov   ecx,dword [0x400000-8]    ; B
    xor   edx,edx                   ; edx:=0
    div   ecx                       ; Xstart/B
   
    ; eax=Int(qn) edx:=Rem
   
    lea   esi,[edx+edx*2]           ; esi:=edx*3
   
    mov   ecx,dword [0x400000-4]    ; ecx:=H
    mov   eax,[esp+4]               ; eax:=Ystart
    xor   edx,edx                   ;
    div   ecx                       ; Ystart/H
   
    mov   eax,edx                   ; eax:=Rem
    xor   edx,edx                   ;
    mov   ebx,[esp+12]              ; ebx:=B*3
    mul   ebx                       ;
    add   esi,eax                   ;
   
    mov   eax,[esi+0x300000]        ; color
    and   eax,0xffffff
   
    mov   ecx, [esp]   ; LFB address
    mov   ebx,eax      ; copy color
    mov   [ecx],bx
    shr   ebx,16
    mov   [ecx+2],bl
   
    xchg  edi, ebp
    mov   ecx,[esp+8]     ; x position
    and   ecx,0x07        ; x modulo 8
    call  setvgapixel     ; eax=color, ecx=x%8, edi=VGA address
    xchg  ebp, edi
   
    pop   ecx
    pop   ebx
    pop   eax
   
  nbgpvga:
   
    inc   eax                       ; x++
    cmp   eax,[draw_data+32+8]      ; X > xend?
    jg    nodp3vga
   
    test  eax,0x07                  ; x test modulo 8
    jnz   hook1vga
    inc   ebp                       ; VGA address++
   
   hook1vga:

    add   ecx,4                     ; LFB address += 4
    inc   edi                       ; ptrBuffer++
    add   esi,3                     ; ptrImage+=3
    jmp   dp3vga
   
  nodp3vga:
   
    mov   eax,[draw_data+32+0]      ; x+Xwin
    inc   ebx                       ; y position
    mov   ecx,eax
    mov   edx,ebx
   
    imul  edx, 640*4           ; (y+Ywin)*BytesPerScanLine
    shl   ecx,2                ; (x+Xwin)*BytesPerPixel
    add   ecx,edx              ;
    mov   ebp,ecx              ; store copy
    add   ecx,[0xfe80]         ; +AddrLFB

    ;entry point in LFB >> ECX:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel+Addr   
   
    shr   ebp,5                ; change from 4 to 1/8 BytesPerPixel
    add   ebp,0xa0000          ; + VGABasePtr

    ;VGA start address >> EBP:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel+AddrV
   
    call  calculate_edi
   
    cmp   ebx,[draw_data+32+12]         ; Y > yend
    jg    dp4vga
   
    jmp   dp3vga
   
  dp4vga:
   
    add   esp,4
   
    pop   edx
    pop   ecx
    pop   ebx
    pop   eax
    pop   ebp
  
    ret
   
; ----------
   
vga_drawbackground_stretch:
   
    push  ebp
    push  eax
    push  ebx
    push  ecx
    push  edx
   
    mov   edx,dword [0x400000-8] ; B
    add   edx,dword [0x400000-8] ; +B
    add   edx,dword [0x400000-8] ; +B
    push  edx
   
    mov   eax,[draw_data+32+0] ; x start:=(x+Xwin)
    mov   ebx,[draw_data+32+4] ; y start:=(y+Ywin)
    mov   ecx,eax
    mov   edx,ebx
   
    imul  edx, 640*4           ; (y+Ywin)*BytesPerScanLine
    shl   ecx,2                ; (x+Xwin)*BytesPerPixel
    add   ecx,edx              ;
    mov   ebp,ecx              ; store copy
    add   ecx,[0xfe80]         ; +AddrLFB

    ;entry point in LFB >> ECX:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel+Addr
   
    shr   ebp,5                ; change from 4 to 1/8 BytesPerPixel
    add   ebp,0xa0000          ; + VGABasePtr

    ;VGA start address >> EBP:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel+AddrV
   
    call  calculate_edi
   
   sdp3vga:                         ; MAIN LOOP
   
    cmp   [edi+0x400000],byte 1     ; ptrBuffer^<>byte(1)
    je    sybgpvga
   
    jmp   snbgpvga
   
  sybgpvga:
   
    push  eax   ; x
    push  ebx   ; y
    push  ecx   ; LFB address
   
    mov   eax,dword [0x400000-8]  ; B
    xor   edx,edx
    mov   ebx,[esp+8]             ; Xstart
    mul   ebx                     ; B*Xstart
    xor   edx,edx
    mov   ebx,[0xfe00]            ; x screen width
    div   ebx                     ; B*Xstart/xwidth
    lea   esi,[eax+eax*2]         ; *3
    mov   eax,dword [0x400000-4]  ; H
    xor   edx,edx
    mov   ebx,[esp+4]             ; Ystart
    mul   ebx                     ; H*Ystart
    xor   edx,edx
    mov   ebx,[0xfe04]            ; y screen height
    div   ebx                     ; H*Ystart/yheight
   
    xor   edx,edx
    mov   ebx,[esp+12]            ; B*3
    mul   ebx                     ;
    add   esi,eax
    mov   eax,[esi+0x300000]      ; color
    and   eax,0xffffff
   
    mov   ecx, [esp]   ; LFB address
    mov   ebx,eax      ; copy color
    mov   [ecx],bx
    shr   ebx,16
    mov   [ecx+2],bl
   
    xchg  edi, ebp
    mov   ecx,[esp+8]     ; x position
    and   ecx,0x07        ; x modulo 8
    call  setvgapixel     ; eax=color, ecx=x%8, edi=VGA address
    xchg  ebp, edi        ; ebp+=3
   
    pop   ecx
    pop   ebx
    pop   eax
   
  snbgpvga:
   
    inc   eax                       ; x++
    cmp   eax,[draw_data+32+8]      ; X > xend?
    jg    snodp3vga
   
    test  eax,0x07                  ; x test modulo 8
    jnz   shook1vga
    inc   ebp                       ; VGA address++
   
   shook1vga:

    add   ecx,4                     ; LFB address += 4
    inc   edi                       ; ptrBuffer++
    add   esi,3                     ; ptrImage+=3
    jmp   sdp3vga
   
  snodp3vga:
   
    mov   eax,[draw_data+32+0]      ; x+Xwin
    inc   ebx                       ; y position
    mov   ecx,eax
    mov   edx,ebx
   
    imul  edx, 640*4           ; (y+Ywin)*BytesPerScanLine
    shl   ecx,2                ; (x+Xwin)*BytesPerPixel
    add   ecx,edx              ;
    mov   ebp,ecx              ; store copy
    add   ecx,[0xfe80]         ; +AddrLFB

    ;entry point in LFB >> ECX:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel+Addr
   
    shr   ebp,5                ; change from 4 to 1/8 BytesPerPixel
    add   ebp,0xa0000          ; + VGABasePtr

    ;VGA start address >> EBP:=(y+Ywin)*BytesPerScanLine+X*BytesPerPixel+A
   
    call  calculate_edi
   
    cmp   ebx,[draw_data+32+12]        ; Y > yend
    jg    sdp4vga
   
    jmp   sdp3vga
   
  sdp4vga:
   
    add   esp,4
   
    pop   edx
    pop   ecx
    pop   ebx
    pop   eax
    pop   ebp
   
    ret
   
   
